package com.gitee.hermer.engine.jars.core.xauth.impl;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.gitee.hermer.boot.jee.commons.bean.utils.BeanLocator;
import com.gitee.hermer.boot.jee.commons.collection.CollectionUtils;
import com.gitee.hermer.boot.jee.commons.collection.StringCache;
import com.gitee.hermer.boot.jee.commons.log.UtilsContext;
import com.gitee.hermer.boot.jee.commons.utils.StringUtils;
import com.gitee.hermer.boot.jee.commons.verify.Assert;
import com.gitee.hermer.engine.jars.core.domain.EngineConstant;
import com.gitee.hermer.engine.jars.core.xauth.IXAuthService;
import com.gitee.hermer.engine.jars.core.xauth.config.XAuthProperties;
import com.gitee.hermer.engine.jars.core.xauth.domain.DynamicMenu;
import com.gitee.hermer.engine.jars.dependent.dsm.IEnginePropertiesAware;
import com.jc.support.auth.web.authc.Account;
import com.jc.support.auth.web.util.AccountUtils;
import com.jc.support.user.bo.DynamicMenuBO;
import com.jc.support.user.service.DynamicMenuService;
import com.jc.support.user.sso.bo.AccountBO;
import com.jc.support.user.sso.service.SSOAccountService;
import com.jc.support.user.token.service.TokenService;

public class XAuthServiceImpl extends UtilsContext implements IXAuthService,IEnginePropertiesAware<XAuthProperties>{

	@Resource
	private TokenService tokenService;
	@Autowired
	@Qualifier("stringRedisTemplate")
	private StringRedisTemplate redisTemplate;

	@Resource
	private SSOAccountService ssoAccountService;
	@Resource
	private DynamicMenuService dynamicMenuService;

	private XAuthProperties properties;


	@Override
	public List<DynamicMenu> getEngineMenus() {
		try {
			if(ssoAccountService.isSuperAdmin(AccountUtils.getId())){
				return generateMenuTree(dynamicMenuService.getAllDynamicMenuBOListOfAppKey(properties.getAppKey()));
			}else{
				return generateMenuTree(dynamicMenuService.getAllPermittedDynamicMenuBOListOfAppKey(properties.getAppKey(), AccountUtils.getId()));
			}
		} catch (Exception e) {
			error(e.getMessage(),e);
		}
		return null;
	}

	HttpServletRequest getRequest(){
		return ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
	}

	@Override
	public Account getCurrentAccount() {
		String token = null;
		HttpServletRequest request = getRequest();
		if(request != null)
			token = request.getParameter(EngineConstant.REQUEST_PARAMS_TOKEN);
		if(StringUtils.isNotBlank(token)){
			Assert.notNull(tokenService);
			AccountBO accountBO = tokenService.getAccountByToken(token);
			return new Account(accountBO.getId(), accountBO.getAccountCode(),null);
		}else{
			return AccountUtils.getCurrentAccount();
		}
	}

	@Override
	public void setCurrentSessionAttribute(String key, String value) {
		HttpServletRequest request = getRequest();
		String token = null;
		if(request != null)
			token = request.getParameter(EngineConstant.REQUEST_PARAMS_TOKEN);
		if(StringUtils.isNotEmpty(token)){
			redisTemplate.opsForValue().set(new StringCache(token).append(StringUtils.DOT).append(key).toString(), value,
					30l,TimeUnit.MINUTES);
		}else{
			org.apache.shiro.SecurityUtils.getSubject().getSession().setAttribute(key, value);
		}
	}

	@Override
	public <T> T getCurrentSessionAttribute(String key) {
		HttpServletRequest request = getRequest();
		String token = null;
		if(request != null)
			token = request.getParameter(EngineConstant.REQUEST_PARAMS_TOKEN);
		if(StringUtils.isNotEmpty(token)){
			return (T) redisTemplate.opsForValue().get(new StringCache(token).append(StringUtils.DOT).append(key).toString());
		}else{
			return (T) org.apache.shiro.SecurityUtils.getSubject().getSession().getAttribute(key);
		}
	}

	@Override
	public String getId() {
		return getCurrentAccount().getId();
	}

	@Override
	public List<DynamicMenu> generateMenuTree(List<DynamicMenuBO> list) {
		try{
			Assert.notEmpty(list);
			list = CollectionUtils.sort(list, new Comparator<DynamicMenuBO>(){
				@Override
				public int compare(DynamicMenuBO o1, DynamicMenuBO o2) {
					return o1.getParentMenuId() == null?-1:0;
				}
			});
			List<DynamicMenu> menuList = new ArrayList<DynamicMenu>();
			for (int i = 0; i < list.size(); i++) {
				if (StringUtils.isBlank(list.get(i).getParentMenuId())) {
					DynamicMenu dest = new DynamicMenu();
					BeanUtils.copyProperties(dest, list.get(i));
					menuList.add(dest);
				}
			}
			for (DynamicMenu menu : menuList) {
				menu.setSubMenu(getChild(menu.getId(), list));
			}
			Assert.notEmpty(menuList);
			return menuList.get(0).getSubMenu();
		}catch (Exception e) {
			error(e.getMessage(),e);
		}
		return null;
	}

	private static List<DynamicMenu> getChild(String id, List<DynamicMenuBO> rootMenu) throws IllegalAccessException, InvocationTargetException {
		List<DynamicMenu> childList = new ArrayList<>();
		for (DynamicMenuBO menu : rootMenu) {
			if (StringUtils.isNotBlank(menu.getParentMenuId())) {
				if (menu.getParentMenuId().equals(id)) {
					DynamicMenu dest = new DynamicMenu();
					BeanUtils.copyProperties(dest, menu);
					childList.add(dest);
				}
			}
		}
		for (DynamicMenu menu : childList) {
			if (StringUtils.isBlank(menu.getMenuUrl())) {
				menu.setSubMenu(getChild(menu.getId(), rootMenu));
			}
		}
		if (childList.size() == 0) {
			return null;
		}
		return childList;
	}

	@Override
	@Autowired
	public void setProperties(XAuthProperties properties) {
		this.properties = properties;
	}


}
